﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace ReporterEngine.Methods
{
    public class Properties : BaseMethod
    {
        public override bool IsUseable(LexPath.PathToken token)
        {
            return token.Kind == LexPath.TokenKind.Property && !string.IsNullOrEmpty(token.PathExp);
        }

        public override sQuery Execute(LexPath.PathToken token, sQuery query)
        {
           // var propertiesName = CIFModel.NormalizeNamesList(propertyNames);

            var propertiesName = query.GetArgValuesForType(token);

            var result = query.New();

            //iterate property names
            foreach (var propertyname in propertiesName)
            {
                var lowerPropertyname = propertyname.ToLower();
                //iterate elements
                foreach (var element in query.Elements)
                {
                    //select predefined names like name, id, oid
                    switch (lowerPropertyname)
                    {
                        case "name":
                            result.Values.Add(query._model.GetName(element));
                            break;
                        case "type":
                            result.Values.Add(query._model.GetTypeName(element));
                            break;
                        case "id":
                            //send squery to retreve id by context, by selected path
                            result.Values.Add(query._model.GetElemenStringtID(element, query));
                            break;
                        case "oid":
                            result.Values.Add(query._model.GetID(element).ToString());
                            break;
                        default:
                            //iterate properties
                            foreach (var prop in element.Elements())
                            {
                                if (query._model.GetPropertyName(prop).ToLower() != lowerPropertyname)
                                {
                                   

                                    bool existsCustomProperty = GetCustomProperty(query, lowerPropertyname, result, element); ;

                                    if(!existsCustomProperty)
                                    {}
                                    //property does not exists
                                }
                                else
                                {
                                    //if is ref
                                    if (prop.Attributes().Where(x => x.Name.LocalName.ToLower() == "refid").Count() == 1)
                                    {
                                        if (prop.Attribute("refid") != null)
                                        {
                                            var refid = prop.Attribute("refid").Value;

                                            if (query._model.IDs.ContainsKey(refid))
                                            {
                                                var sourceEl = query._model.IDs[refid];
                                                result.Elements.Add(sourceEl);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        //System.Security.SecurityElement.
                                        
                                        //if is value
                                        result.Values.Add(EncodeToString(prop.Value));
                                    }
                                }
                            }
                            break;
                    }
                }
            }
            result.Elements = result.Elements.Distinct(new CIFModel.NodeComparer()).ToList();

            result.Elements = result.Elements.OrderBy(x=> query._model.GetElemenID(x, query)).ToList();

            return result;
        }

        string EncodeToString(string source)
        {
            var result = source;

            result = result
                .Replace("&amp;", "&")
                .Replace("&lt;", "<")
                .Replace("&gt;", ">")
                .Replace("&quot;", "\"")
                .Replace("&apos;", "'")

                .Replace("amp;", "&")
                .Replace("lt;", "<")
                .Replace("gt;", ">")
                .Replace("quot;", "\"")
                .Replace("apos;", "'");
                

            return result;
        }

        private bool GetCustomProperty(sQuery query, string lowerPropertyname, sQuery result, XElement element)
        {
            if (element.Element("customProperties") != null)
            {
                var customProperties = element.Element("customProperties");

                var customElement =
                    customProperties.Elements("customProperty").Where(
                        x =>
                        x.Attribute("name") != null &&
                        x.Attribute("name").Value.ToLower() == lowerPropertyname).FirstOrDefault();

                if (customElement != null)
                {
                    var resvalue = customElement.Element("value").Value;

                    //typref
                    if (string.IsNullOrEmpty(resvalue) &&
                        customElement.Attribute(XName.Get("typref")) != null)
                    {
                        //get default value
                        var refTypeValue = customElement.Attribute(XName.Get("typref")).Value;
                        var defTypeValue = query._model.IDs[refTypeValue];

                        if (defTypeValue != null &&
                            defTypeValue.Element(XName.Get("default")) != null)
                        {
                            resvalue = defTypeValue.Element(XName.Get("default")).Value;
                        }
                    }

                    result.Values.Add(EncodeToString(resvalue));
                    return true;
                }
                else
                {
                    //find in definitions
                    //notebook/types/customConfigurations/customConfiguration/objectTypes/objectType

                    var elementName = element.Name.LocalName;

                    var objectType = query._model.Notebook
                        .Element(XName.Get("types"))
                        .Element(XName.Get("customConfigurations"))
                        .Element(XName.Get("customConfiguration"))
                        .Element(XName.Get("objectTypes"))
                        .Elements(XName.Get("objectType"))
                        .Where(x => x.Attribute(XName.Get("name")).Value == elementName).
                        FirstOrDefault();

                    foreach (
                        var customTypes in
                            objectType.Element(XName.Get("customPropertyTypes")).Elements(
                                XName.Get("customPropertyType")))
                    {
                        var refTypeID = customTypes.Attribute(XName.Get("refid")).Value;

                        var defTypeValue = query._model.IDs[refTypeID];

                        if (lowerPropertyname ==
                            defTypeValue.Attribute(XName.Get("name")).Value.ToLower())
                        {
                            if (defTypeValue.Element(XName.Get("default")) != null)
                            {
                                result.Values.Add(defTypeValue.Element(XName.Get("default")).Value);
                            }

                            return true;
                        }
                    }
                }
            }

            return false;
        }

        //private string GetElemenStringtID(sQuery query, XElement element)
        //{
        //    var numbering = "";

        //    if (element != null && element.Element("numberPrefix") != null)
        //    {
        //        var parent = element;

        //        while (parent != null && parent.Element("numberPrefix") != null)
        //        {
        //            if (string.IsNullOrEmpty(numbering))
        //                numbering = numberPrefix(parent);
        //            else
        //                numbering = numberPrefix(parent) + "." + numbering;

        //            if (numbering == ".3.2")
        //            {
        //                int ee = 12;
        //                //vyhladavanie organization parenta
        //            }


        //            if (parent.Element("parent") != null)
        //            {
        //                var refid = parent.Element("parent").Attribute("refid").Value;
        //                parent = query._model.IDs[refid];
        //            }
        //            else
        //                parent = null;
        //        }
        //    }

        //    return numbering;
        //}

        public override MethodDescription[] GetMethodNames()
        {
            return new MethodDescription[]{new MethodDescription{IsUserMethod = false} };
        }

        //public static string numberPrefix(XElement element)
        //{
        //    if (element.Element("numberPrefix") != null)
        //    {
        //        string numValue = element.Element("numberPrefix").Value;

        //        string prefixStyle = element.Element("prefixStyle").Value;


        //        if (prefixStyle == "numeric")
        //            return numValue;

        //        if (prefixStyle == "alphaExtended")
        //        {
        //            if (Int64.Parse(numValue) >= 0)
        //            {
        //                var totalVal = Int64.Parse(numValue);

        //                var currentVal = totalVal;

        //                var resText = "";

        //                if (totalVal == 70)
        //                {
        //                    int ee = 12;
        //                }

        //                while (currentVal > 24)
        //                {
        //                    var zvysok = currentVal % 26;
        //                    var podiel = (currentVal - zvysok) / 26;

        //                    byte curByte = (byte)zvysok;
        //                    curByte += (byte)'A' - 1;
        //                    char curChar = (char)curByte;

        //                    resText = curChar.ToString() + resText;

        //                    currentVal = podiel;
        //                }


        //                byte lastByte = (byte)currentVal;
        //                lastByte += (byte)'A' - 1;
        //                char lastChar = (char)lastByte;

        //                resText = lastChar.ToString() + resText;


        //                return resText;
                  
        //            }
        //        }
        //    }

        //    return "";
        //}
    }
}
